package com.spring.springboot.controller;

import java.util.Date;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.spring.springboot.entity.TokenInfoEntity;
import com.spring.springboot.entity.TokenResult;
import com.spring.springboot.entity.UserInfoEntity;
import com.spring.springboot.jpa.TokenJPA;
import com.spring.springboot.jpa.UserInfoJPA;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

/**
 * ========================
 * Created with IntelliJ IDEA.
 * User：恒宇少年
 * Date：2017/4/22
 * Time：22:40
 * 码云：http://git.oschina.net/jnyqy
 * ========================
 */
@RestController
@RequestMapping(value = "/jwt")
public class TokenController{

	@Autowired
	private TokenJPA tokenJPA;

	@Autowired
	private UserInfoJPA userJPA;
	
	@RequestMapping(value = "/token", method = {RequestMethod.GET, RequestMethod.POST})
	public TokenResult token(@RequestParam String appId, @RequestParam String appSecret) {
		TokenResult token = new TokenResult();
		
		if(appId == null || "".equals(appId)) {
			token.setFlag(false);
			token.setMsg("appId is not found");
		}else if(appSecret == null || "".equals(appSecret)) {
			token.setFlag(false);
			token.setMsg("appSecret is not found");
		}else {
			Optional<UserInfoEntity> optional = userJPA.findOne(new Specification<UserInfoEntity>() {
				
				@Override
				public Predicate toPredicate(Root<UserInfoEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
					query.where(criteriaBuilder.equal(root.get("appId"), appId));
					return null;
				}
			});
			UserInfoEntity userDBInfo = optional.get();
			if(userDBInfo == null) {
				token.setFlag(false);
				token.setMsg("appId:" + appId + ", isnot found");
			}else if(!new String (userDBInfo.getAppSecret()).equals(appSecret.replaceAll(" ", "+"))) {
				token.setFlag(false);
				token.setMsg("appSecret is not effective!");
			}else {
				Optional<TokenInfoEntity> optional1 = tokenJPA.findOne(new Specification<TokenInfoEntity>() {
					@Override
					public Predicate toPredicate(Root<TokenInfoEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
						query.where(criteriaBuilder.equal(root.get("appId"), appId));
						return null;
					}
				});
				
				TokenInfoEntity tokenDBInfo = optional1.get();
				String tokenStr = null;
				if(tokenDBInfo == null) {
					tokenStr = createNewToken(appId);
					tokenDBInfo = new TokenInfoEntity();
					tokenDBInfo.setAppId(userDBInfo.getAppId());
					tokenDBInfo.setBuildTime(String.valueOf(System.currentTimeMillis()));
					tokenDBInfo.setToken(tokenStr.getBytes());
					tokenJPA.save(tokenDBInfo);
				}else {
					long dbBuidTime = Long.valueOf(tokenDBInfo.getBuildTime());
					long currentTime = System.currentTimeMillis();
					long second = TimeUnit.MILLISECONDS.toSeconds(currentTime - dbBuidTime);
					if(second > 0 && second < 7200 ) {
						tokenStr = new String (tokenDBInfo.getToken());
					}else {
						tokenStr = createNewToken(appId);
						tokenDBInfo.setToken(tokenStr.getBytes());
						tokenDBInfo.setBuildTime(String.valueOf(System.currentTimeMillis()));
						tokenJPA.save(tokenDBInfo);
					}
					
					
				}
				token.setToken(tokenStr);
			}
		}
		
		return token;
	}
	
	private String createNewToken(String appId) {
		
		Date now = new Date(System.currentTimeMillis());
		Date expiration = new Date(now.getTime() + 7200);
		return Jwts
				.builder()
				.setSubject(appId)
				.setIssuedAt(now)
				.setIssuer("online YAuth Builder")
				.setExpiration(expiration)
				.signWith(SignatureAlgorithm.HS256, "YINGEAUthv1.0.0")
				.compact();
	}
	
}
